package chromosomes;

import java.util.Random;

import logic.TreeBin;

public class Chromosome {

	private TreeBin tree;
	private double fitness;
	private double punt;
	private double puntAccumulated;

	public Chromosome() {
		int minDepth = 2;//new Random().nextInt(2) + 1;
		int maxDepth = 6;//new Random().nextInt(2) + minDepth;
		createChromosome(minDepth, maxDepth);
	}

	public Chromosome(int minDepth, int maxDepth) {
		createChromosome(minDepth, maxDepth);
	}

	public Chromosome(TreeBin tree) {
		setTree((TreeBin) tree);
		evaluate();
	}
	
	public double evaluate() {
		int corrects = 0;
		boolean[] d = new boolean[4];
		boolean[] a = new boolean[2];
		int max = (int) Math.pow(2, d.length + a.length);
		for (int i = 0; i < max; i++) {
			boolean optimum = optimum(a, d);
			boolean treeEvaluate = tree.evaluate(a, d);
			if (optimum == treeEvaluate) {
				corrects++;
			}
			plus1(a, d);
		}
		return fitness = corrects;
	}

	public double getFitness() {
		return fitness;
	}

	public double getpAccumulated() {
		return puntAccumulated;
	}

	public double getpSelection() {
		return punt;
	}

	public TreeBin getTree() {
		return tree;
	}

	public void mutate(double mutateProb) {
		tree.mutate(mutateProb);
	}

	public void replaceSubTree(int node, TreeBin tree) {
		this.tree.sustitute(node, tree);
	}

	public void setFitness(double fitness) {
		this.fitness = fitness;
	}

	public void setpAccumulated(double p) {
		puntAccumulated = p;
	}

	public void setpSelection(double p) {
		punt = p;
	}

	public void setTree(TreeBin tree) {
		this.tree = tree;
	}

	@Override
	protected Object clone() {
		return new Chromosome(tree);
	}

	private void createChromosome(int minDepth, int maxDepth) {
		tree = new TreeBin(minDepth, maxDepth, null);
		evaluate();
	}

	private boolean optimum(boolean[] as, boolean[] ds) {
		if (as[1] && as[0]) {
			return ds[3];
		} else if (as[1]) {
			return ds[2];
		} else if (as[0]) {
			return ds[1];
		} else {
			return ds[0];
		}
	}

	private void plus1(boolean[] a, boolean[] d) {
		boolean carry = true;
		for (int i = 0; i < d.length; i++) {
			boolean aux = carry && d[i];
			d[i] = carry ^ d[i];
			carry = aux;
		}
		for (int i = 0; i < a.length; i++) {
			boolean aux = carry && a[i];
			a[i] = carry ^ a[i];
			carry = aux;
		}
	}

	@Override
	public String toString() {
		String t = tree.toString();
		return "Fitness: " + fitness + "\n" + t.substring(1, t.length());
	}

}
